#include "interface_fil_master.h"
#include <QDebug>
#include <QRegExp>
#include <QFileInfo>
interface_fil_master::interface_fil_master()
{
    // --------------------------------------------
    // 声明总线类型
    table->setItem(1-1, 1-1, new QTableWidgetItem(QString("itf_type")));
    table->setItem(1-1, 2-1, new QTableWidgetItem(QString("fil")));
    // --------------------------------------------
    // 连接逻辑
    connect(this,&interface_mdle::itf_out_rx, //主机接收信号
            this,&interface_fil_master::recv_itf_slot); //主机接收逻辑

}
// --------------------------------------------
// 反馈总线内容
void interface_fil_master::recv_itf_slot(QVariantList &itfs)
{
    if(!itfs.at(0).canConvert<itf_fil>()) //类型检查,类型不对不执行，只检查一个数据包，后续协议如果拓展，可以同时发送多个包
    {
        QDEBUG << "slaver data, and match status is " << false;
        return;
    }

    recv_fil = itfs.at(0).value<itf_fil>(); //缓存接收的结构体方便后续使用，因为信号是器件先收到，所以不需要再返回给器件
    emit recv_fil_trig(recv_fil); //IO就绪，由器件决定响应的逻辑

}

QString interface_fil_master::get_recv_fil_type()
{
    return QString::fromUtf8(recv_fil.type, 4);
}
// --------------------------------------------
// 给总线特定格式数据（内置一些通用的发送方法）
void interface_fil_master::master_send_list()
{
    send_fil.id = 0x0;
    send_fil.size = 0x0; //无文件内容，纯指令
    int len = sizeof(send_fil.addr) / sizeof(quint32); //获取目录级数
    for(int i = 0; i < len; i++)
    {
        send_fil.addr[i] = 0x0;
    }
    //| strcpy(send_fil.type,"list"); //确保长度为4字节,该方式不保险
    memcpy(send_fil.type,"list",4);
    send_fil.data.clear(); //无数据负载
    qDebug() << __FILE__ << __LINE__ << "m_fil size is:" << send_fil.size;

    //预设的指令直接触发
    QVariantList list;
    list << QVariant::fromValue(send_fil);
    emit itf_out_tx(list); //主机发送数据
}


// --------------------------------------------
// 解析特定格式的数据（内置一些通用的解析方法）
QStringList interface_fil_master::master_recv_list()
{
    QStringList md_title = {}; //获取md格式的目录
    QString type = QString::fromUtf8(recv_fil.type, 4); // 只处理前4个字符

    if(type == "list") //检查一下格式是否正确
    {
        int dir_len = sizeof(recv_fil.addr) / sizeof(quint32); //获取目录级数
        int info_len = 4 * 2 + sizeof(recv_fil.addr); //缓存信息的长度
        for(int i = 0; i < int(sizeof(recv_fil.data)); i = i + info_len)
        {
            QString title;
            int dir_len_valid = 0;
            //获取目录结构
            QString raw_title;
            for(int j = 0; j < dir_len; j++)
            {
                raw_title = recv_fil.data.mid(i*info_len+j*4+8, sizeof(quint32)).toHex();
                qDebug() << "raw_title" << raw_title;
                if(raw_title == "00000000") //目录结束，不再生成
                {
                    dir_len_valid = j;
                    break;
                }
                title.clear();
                title.fill('#',j+1);
                title += " ";
                title += raw_title;
                md_title.append(title);
                dir_len_valid = j;
            }
            //额外执行一次，将文件内容挂载目录下
                title.clear();
                title.fill('#',dir_len_valid+1);
                title += " ";
                raw_title = recv_fil.data.mid(i*info_len+0, sizeof(quint32)).toHex();
                title += raw_title; //加载文件名
                raw_title = recv_fil.data.mid(i*info_len+4, sizeof(quint32)).toHex();
                title += "+:"; //加载数据长度
                title += raw_title; //加载数据长度
                md_title.append(title);
                QDEBUG << recv_fil.data.mid(i*info_len+0, info_len ).toHex();
        }

    }
    return md_title; //解析出对应的目录
}
// --------------------------------------------
// 写入文件信息
void interface_fil_master::master_send_save(QString basedir, QString basename)
{
    QDir  dir  = QDir(basedir);
    if (!dir.exists())
    {
        QDEBUG << basedir << "not exist";
    }
    QString pns_name = dir.filePath(basename);
    QFile file(pns_name); //! 获取文件
    QFileInfo info(pns_name);
    if (!file.exists()) {
        QDEBUG << pns_name << "not exist";
        return;
    }
    QString name = info.baseName(); //获取文件名，要求以8字节16进制数字表示，不然不支持
    QRegExp hexRegExp("^[0-9a-fA-F]{8}$");
    if(hexRegExp.exactMatch(name) == 0)
    {
        QDEBUG << name << "must like 00112233";
        return;
    }
    QStringList addrs = basename.split("/");
    for(int i = 0; i < addrs.size() - 1; i ++)
    {
        if(hexRegExp.exactMatch(addrs.at(i)) == 0)
        {
            QDEBUG << addrs.at(i) << "must like 00112233";
            return;
        }
        else if(addrs.at(i) == "00000000")
        {
            QDEBUG << addrs.at(i) << "cannot set 00000000";
            return;
        }
    }
    //写入文件
    file.open(QIODevice::ReadOnly);
    bool ok;
    send_fil.id = name.midRef(0,8).toUInt(&ok,16);
    send_fil.size = file.size(); //获取文件的大小
    memcpy(send_fil.type,"save",4);
    int dir_len = sizeof(recv_fil.addr) / sizeof(quint32);
    for(int i = 0; i < dir_len; i ++)
    {
        if(i < addrs.size() - 1 && addrs.size() > 1) //除了文件名外，其他目录全部加载
        {
            send_fil.addr[i] = addrs.at(addrs.size()-2-i).midRef(0,8).toUInt(&ok,16);
        }
        else
        {
            send_fil.addr[i] = 0x00000000; //结束地址
        }
    }
    send_fil.data.clear();
    send_fil.data = file.readAll();
    file.close();

    //预设的指令直接触发
    QVariantList list;
    list << QVariant::fromValue(send_fil);
    emit itf_out_tx(list); //主机发送数据

    return;
}

QString interface_fil_master::master_recv_save(QString basedir)
{
    QDir dir = QDir(basedir);
    if (!dir.exists())
    {
        QDEBUG << basedir << "not exist";
        return "";
    }
    QString type = QString::fromUtf8(recv_fil.type, 4); // 只处理前4个字符
    if(type != "save")
    {
        QDEBUG << basedir << "not exist";
        return "";
    }
    //解析出文件的相对路径以及文件名
    QString basename;
    QString return_name; //返回的名字
    int dir_len = sizeof(recv_fil.addr) / sizeof(quint32); //获取目录级数
    for(int i = 0; i < dir_len; i++)
    {
        if(recv_fil.addr[dir_len-1-i]!=0x0) //寻找第一个有效地址
        {
            QString str =  QString("%1").arg(recv_fil.addr[dir_len-1-i], 8, 16, QChar('0')).toUpper();
            basename.append(str);
            basename.append("/");
        }
    }
    QString str =  QString("%1").arg(recv_fil.id, 8, 16, QChar('0')).toUpper();
    basename.append(str);
    return_name = basename; //前面保持一致
    basename.append(".bit"); //! 嵌入式文件系统，默认都以bit为后缀
    return_name.append("+:");
    return_name.append(QString("%1").arg(recv_fil.size, 8, 16, QChar('0')).toUpper());
    // --------------------------------------------
    // 文件内容到本地的目录
    QString pns_name = dir.filePath(basename);
    QFileInfo fileInfo(pns_name);
    QString  dir_str = fileInfo.path();
    QDir dir_mk;
    dir_mk.mkdir(dir_str); //创建缓存目录
    //读取文件，校验写入的大小
    QFile file(pns_name);
    if (!file.open(QIODevice::ReadOnly)) {
        QDEBUG << "open fail:" << pns_name;
        return "";
    }
    quint32 wr_len = file.size(); //获取文件
    if(wr_len != recv_fil.size)
    {
        QDEBUG << "save size not match:" << file.errorString();
    }
    file.close();

    return return_name;
}

void interface_fil_master::master_send_load(QString basedir, QString basename)
{
    QDir  dir  = QDir(basedir);
    if (!dir.exists())
    {
        QDEBUG << basedir << "not exist";
    }
    QString pns_name = dir.filePath(basename);
    QFile file(pns_name); //! 获取文件
    QFileInfo info(pns_name);
    if (!file.exists()) {
        QDEBUG << pns_name << "not exist";
        return;
    }
    QString name = info.baseName(); //获取文件名，要求以8字节16进制数字表示，不然不支持
    QRegExp hexRegExp("^[0-9a-fA-F]{8}$");
    if(hexRegExp.exactMatch(name) == 0)
    {
        QDEBUG << name << "must like 00112233";
        return;
    }
    QStringList addrs = basename.split("/");
    for(int i = 0; i < addrs.size() - 1; i ++)
    {
        if(hexRegExp.exactMatch(addrs.at(i)) == 0)
        {
            QDEBUG << addrs.at(i) << "must like 00112233";
            return;
        }
        else if(addrs.at(i) == "00000000")
        {
            QDEBUG << addrs.at(i) << "cannot set 00000000";
            return;
        }
    }
    //写入文件
    file.open(QIODevice::ReadOnly);
    bool ok;
    send_fil.id = name.midRef(0,8).toUInt(&ok,16);
    send_fil.size = file.size(); //获取文件的大小
    memcpy(send_fil.type,"load",4);
    int dir_len = sizeof(recv_fil.addr) / sizeof(quint32);
    for(int i = 0; i < dir_len; i ++)
    {
        if(i < addrs.size() - 1 && addrs.size() > 1) //除了文件名外，其他目录全部加载
        {
            send_fil.addr[i] = addrs.at(addrs.size()-2-i).midRef(0,8).toUInt(&ok,16);
        }
        else
        {
            send_fil.addr[i] = 0x00000000; //结束地址
        }
    }
    send_fil.data.clear();
    //send_fil.data = file.readAll();
    file.close();

    //预设的指令直接触发
    QVariantList list;
    list << QVariant::fromValue(send_fil);
    emit itf_out_tx(list); //主机发送数据

    return;
}

QString interface_fil_master::master_recv_load(QString basedir)
{
    QDir dir = QDir(basedir);
    if (!dir.exists())
    {
        QDEBUG << basedir << "not exist";
        return "";
    }
    QString type = QString::fromUtf8(recv_fil.type, 4); // 只处理前4个字符
    if(type != "load")
    {
        QDEBUG << basedir << "not exist";
        return "";
    }
    //解析出文件的相对路径以及文件名
    QString basename;
    int dir_len = sizeof(recv_fil.addr) / sizeof(quint32); //获取目录级数
    for(int i = 0; i < dir_len; i++)
    {
        if(recv_fil.addr[dir_len-1-i]!=0x0) //寻找第一个有效地址
        {
            QString str =  QString("%1").arg(recv_fil.addr[dir_len-1-i], 8, 16, QChar('0')).toUpper();
            basename.append(str);
            basename.append("/");
        }
    }
    QString str =  QString("%1").arg(recv_fil.id, 8, 16, QChar('0')).toUpper();
    basename.append(str);
    basename.append(".bit"); //! 嵌入式文件系统，默认都以bit为后缀
    // --------------------------------------------
    // 写入文件内容到本地的目录
    QString pns_name = dir.filePath(basename);
    QFileInfo fileInfo(pns_name);
    QString  dir_str = fileInfo.path();
    QDir dir_mk;
    dir_mk.mkdir(dir_str); //创建缓存目录
    //读取文件，校验写入的大小
    QFile file(pns_name);
    if (!file.open(QIODevice::WriteOnly)) {
        QDEBUG << "open fail:" << file.errorString();
        return "";
    }

    quint32 wr_len = file.write(recv_fil.data); //写入数据到文件
    if(wr_len != recv_fil.size)
    {
        QDEBUG << "save size not match:" << file.errorString();
    }
    file.close();

    return basename;
}


